//! 实现Self::orm_exist相关方法

use proc_macro2::TokenStream as TokenStream2;
use quote::{format_ident, quote};
use syn::{
    parse_str, Lit, Meta, MetaList, MetaNameValue,
    NestedMeta, Type,
};

/// 实现struct的Self::orm_exist方法
pub(super) fn impl_struct_orm_exist(ast: &syn::DeriveInput) -> Option<TokenStream2> {
    // 解析orm_query
    let mut fn_imps = vec![];
    for orm_query_attrs in  ast.attrs.iter().filter_map(|attr| {
        if attr.path.is_ident("orm_exist") {
            attr.parse_meta().ok().map(|meta| {
                if let Meta::List(MetaList{nested,..}) = meta{
                    let args:Vec<_> = nested.iter().filter_map(|nested_meta|{
                        if let NestedMeta::Meta(Meta::NameValue(MetaNameValue{path,lit,..})) = nested_meta{
                            let name = path.get_ident().unwrap().to_string();
                            if path.is_ident("name") || path.is_ident("sql_where") || path.is_ident("args") || path.is_ident("doc"){
                                match lit{
                                    Lit::Str(lit_str) => Some((name,lit_str.value())),
                                    _ => panic!("orm_exist 参数说明,正确参数为:name、sql_where、arg_num和doc"),
                                }
                            }else{
                                None
                            }
                        }else{
                            None
                        }
                    }).collect();
                    args
                }else{
                    panic!("orm_exist 属性设置错误")
                }
            })
        } else {
            None
        }
    }){
        // 获取函数名称
        let fn_last_name = orm_query_attrs.iter().find_map(|(name,value)| (name=="name")
            .then_some(value)).expect("获取函数名称定义");
        // sql where语句,可选,默认1=1，所有
        let sql_where = orm_query_attrs.iter().find_map(|(name,value)| (name=="sql_where")
            .then_some(value.as_str())).unwrap_or("1=1");

        let arg_names = orm_query_attrs.iter().find_map(|(name,value)| (name=="args")
            .then_some(value)).expect("获取函数查询参数定义").split(',').map(|arg_str|{
            let mut arg_sp = arg_str.split(':');
            let arg_name = arg_sp.next().expect("获取函数参数名称");
            format_ident!("{}",arg_name)
        }).collect::<Vec<_>>();
        // 解析参数定义，格式为name:&str,mobile_num:&str
        let arg_types = orm_query_attrs.iter().find_map(|(name,value)| (name=="args")
            .then_some(value))
            .expect("获取函数查询参数定义")
            .split(',')
            .map(|arg_str|{
            let mut arg_sp = arg_str.split(':');
            let arg_type = arg_sp.nth(1).expect("获取函数参数类型");
            let arg_type:Type = parse_str(arg_type).expect("解析函数参数类型");
            arg_type
        }).collect::<Vec<_>>();
        let doc= orm_query_attrs.iter().find_map(|(name,value)| (name=="doc")
            .then_some(value))
            .map_or_else(|| String::from("tiny orm 实现方法,{fn_last_name}"), 
                |info| format!("tiny orm 实现方法，{info}"));
        let fn_name = format_ident!("orm_exist_with_{}", fn_last_name);
        fn_imps.push(quote!{
            #[doc = #doc]
            pub async fn #fn_name(pool: &TinyOrmDbPool, #(#arg_names: #arg_types),*) ->AnyhowResult<bool>
            {
                let sql = Self::DB_META.build_exist_sql(#sql_where);
                let row: (i64,) = query_as(&sql)
                    #(.bind(#arg_names))*
                    .fetch_one(pool)
                    .await
                    .with_context(|| "查询记录是否存在时出错!")?;
                Ok(row.0 > 0)
            }
        });
    }
    (!fn_imps.is_empty()).then(|| {
        quote! {
                #(
                    #fn_imps
                )*
        }
    })
}